#ifndef __MATRIX_h
#define __MATRIX_h

#include<iostream>
#include<stdio.h>


void exitAbnormal(int error_code);

template<typename T>
class Matrix
{
    public:
    int n_row;
    int n_col;
    T *ele;

    Matrix(int i,int j,T *k)      ///constructor
    {
        n_row=i;
        n_col=j;
        ele=new T[i*j];
        for(int l=0;l<i*j;l++)
        {
            ele[l]=k[l];
        }
    }

    Matrix(int i,int j)        ///constructor
    {
        n_row=i;
        n_col=j;
        ele=new T[i*j];
        for(int l=0;l<i*j;l++)
        {
            ele[l]=0;
        }
    }

    ~Matrix()                   ///destructor
    {
        if (ele != NULL )
	    delete [] ele;
        ele = NULL;
    }

    bool is_square()              /// to identify whether the matrix is square
    {
        if(n_col==n_row)
        return true;
        else
        return false;
    }

    Matrix<T>& operator=(const Matrix<T>& b)           ///to reload =
    {
        n_row=b.n_row;
        n_col=b.n_col;
        for(int i=0;i<b.n_row*b.n_col;i++)
        {
            ele[i]=b.ele[i];
        }
        return *this;
    }

    void show();                                       ///to make matrix visble
};

template<typename T>
void Matrix<T>::show()                                
{
    for(int i=0;i<n_row;i++)
    {
        for(int j=0;j<n_col;j++)
        {
            std::cout<<ele[i*n_col+j];
        }
        std::cout<<"\n";
    }
}

template<typename T>
class RowVector: public Matrix<T>                           ///class rowvector
{
    public:

    RowVector(int n, T* k):Matrix<T>(1,n,k){}
    RowVector(int n):Matrix<T>(1,n){}

};

template<typename T>
class ColVector : public Matrix<T>                         ///class colvector
{
    public:

    ColVector(int n, T* k):Matrix<T>(n,1,k){}
    ColVector(int n):Matrix<T>(n,1){}
};

template<typename T>
T operator*(const RowVector<T>& a,const ColVector<T>& b)                 ///reload operator*
{
    T sum1=0;
    if (a.n_col!=b.n_row)
	exitAbnormal(1);
    for(int i=0;i<a.n_col;i++)
    {
        sum1+=a.ele[i]*b.ele[i];
    }                           
    return sum1;                              
}

template<typename T>
T operator*(const RowVector<T>& a,const RowVector<T>& b)                ///reload operator*
{
    T sum1=0;
    if (a.n_col!=b.n_col)
	exitAbnormal(2);
    for(int i=0;i<a.n_col;i++)
    {
        sum1+=a.ele[i]*b.ele[i];
    }                           
    return sum1; 
}

template<typename T>
T operator*(const ColVector<T>& a,const ColVector<T>& b)                   ///reload operator*
{
    T sum1=0;
    if (a.n_row!=b.n_row)
	exitAbnormal(3);
    for(int i=0;i<a.n_row;i++)
    {
        sum1+=a.ele[i]*b.ele[i];
    }                           
    return sum1; 
}

template<typename T>
const Matrix<T> operator*(const Matrix<T>& a, const Matrix<T>& b)                ///reload operator*
{
    if (a.n_col!=b.n_row)
	exitAbnormal(4);
    Matrix<T> c(a.n_row, b.n_col);
    for (int i=0; i<a.n_row; i++)
    {
    for (int j=0; j<b.n_col; j++)
        {
            for (int k = 0; k<a.n_col; k++)
            {
                c.ele[i*b.n_col+j]=c.ele[i*b.n_col+j]+a.ele[i*a.n_col+k]*b.ele[j+k*b.n_col];
            }
        }
    }
    return c;
}

void exitAbnormal(int error_code)              ///in case several types of errors
{
    switch (error_code)
    {
    case 1:
	std::cerr << "The lengths of rowvector and colvector do not match." << std::endl;
	break;
    case 2:
    std::cerr << "The lengths of rowvector and rowvector do not match." << std::endl;
	break;
    case 3:
	std::cerr << "The lengths of colvector and colvector do not match." << std::endl;
	break;
    case 4:
	std::cerr << "The dimensions of two matrixs do not match." << std::endl;
	break;
    default:
	break;
    }
    std::terminate();
};

#else
#endif
